﻿using System;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Threading;
//Zachary Behrmann & Rob Husfeldt
//Honestly, we modified most of this class, largely by making it so that we used the picturebox store in creature than a global one.
namespace ParsingProject {

    /// <summary>
    /// The controller and the view for a parser that moves an object.
    /// <list type="bullet">
    /// <item>
    /// <term>Authors:</term>
    /// <description>David I. Schwartz</description>
    /// <description>Sela Davis</description>
    /// </item>
    /// </list>
    /// </summary>
    public partial class Parser : Form {

        #region fields

        private Creature creature;         // creature to move
        private Creature otherCreature;
        private string expression;         // expression to parse
        private const int DISTANCE = 25;   // number of pixels to move each time
        private const int DELAY = 250;     // delay between parsed expression steps
        private Creature.DIRECTION curDir; // current direction of creature
        private Queue<MotionPair> moves;   // sequence of actions and amounts parsed from expression
        private Queue<MotionPair> moves2;   // sequence of actions and amounts parsed from expression
        private const string imagePath =   // image pathname
                  "..\\..\\arrow.bmp";

        #endregion fields

        #region construction and set up

        /// <summary>
        /// Make an instance of the current "game."
        /// </summary>
        public Parser() {
            InitializeComponent();
            setUp();
        }

        /// <summary>
        /// Reset the current board, set up Creature, and set up Tokenizer.
        /// </summary>
        private void setUp() {
            pictureBox.Image = Image.FromFile(imagePath);
            pictureBox.Location = new Point(splitContainer.Panel2.Width / 2, splitContainer.Panel2.Height / 2);

            pictureBox1.Image = Image.FromFile(imagePath);
            pictureBox1.Location = new Point(splitContainer.Panel2.Width / 4, splitContainer.Panel2.Height / 4);

            creature = new Creature(pictureBox.Location.X, pictureBox.Location.Y, "I");
            otherCreature = new Creature(pictureBox1.Location.X, pictureBox1.Location.Y, "He");
            creature.Boxxy = pictureBox;
            otherCreature.Boxxy = pictureBox1;
            moves = null;
            moves2 = null;
            curDir = creature.Orientation;
            expression = "";
            parseTextBox.Text = "";
            responseTextBox.Text = "";
        }

        #endregion construction and set up

        #region motion

        /// <summary>
        /// Update the view based on current command name and value.
        /// </summary>
        /// <param name="action">pair of name and value</param>
        private void animate(MotionPair action, Creature cretin) {
            string move = action.Motion;
            int amount = action.Amount;

            // try to translate or rotate:
            switch (move) {
                case "turn":
                    if (amount == 90)
                        rotateClockwise(cretin);
                    else if (amount == 180)
                    {
                        rotateClockwise(cretin);
                        System.Threading.Thread.Sleep(DELAY);
                        rotateClockwise(cretin);
                    }
                    else if (amount == 360)
                    {
                        rotateClockwise(cretin);
                        System.Threading.Thread.Sleep(DELAY);
                        rotateClockwise(cretin);
                        System.Threading.Thread.Sleep(DELAY);
                        rotateClockwise(cretin);
                        System.Threading.Thread.Sleep(DELAY);
                        rotateClockwise(cretin);
                    }
                    break;
                case "move":
                    translate(amount, cretin);
                    break;
                case "die":
                    MessageBox.Show("Sorry you feel that way, hope your day goes better!", "Killed yourself!", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
                    this.Close();
                    break;
                case "roll":
                    rotateClockwise(cretin);
                    System.Threading.Thread.Sleep(DELAY);
                    translate(1, cretin);
                break;
                default:
                    throw new Exception();
            }

            // delay to provide animation:
            System.Threading.Thread.Sleep(DELAY);

        } // method animate

        /// <summary>
        /// Move the creature in the view based on current location, parsed amount, and default # of pixels.
        /// </summary>
        /// <param name="move">how many times the creature needs to move</param>
        private void translate(int move, Creature cretin) {

            // get current creature position:
            int tmpX = cretin.X;
            int tmpY = cretin.Y;

            // how much do we need to move in current direction?
            // use GUI's default # of pixels:
            int delta = move * DISTANCE;
            switch (cretin.Orientation) {
                case Creature.DIRECTION.NORTH:
                    tmpY -= delta;
                    break;
                case Creature.DIRECTION.SOUTH:
                    tmpY += delta;
                    break;
                case Creature.DIRECTION.EAST:
                    tmpX += delta;
                    break;
                case Creature.DIRECTION.WEST:
                    tmpX -= delta;
                    break;
                default:
                    break;
            }

            // if we cannot move delta, alert user
            // otherwise, move creature and redraw position:
            Point p = new Point(tmpX, tmpY);
            if (outOfBounds(p)) {
                MessageBox.Show("Creature cannot leave board area.");
                throw new Exception();
            }
            else {
                cretin.Boxxy.Location = p;
                cretin.X = tmpX;
                cretin.Y = tmpY;
            }

        } // method translate


        /// <summary>
        /// Is Point p within the board bounds? (Panel2)
        /// </summary>
        /// <param name="p">Point to check</param>
        /// <returns>true if out of bounds, otherwse false</returns>
        private bool outOfBounds(Point p) {
            return (
                p.X < 0 ||
                p.Y < 0 ||
                (p.X + pictureBox.Image.Width) > splitContainer.Panel2.Width ||
                (p.Y + pictureBox.Image.Height) > splitContainer.Panel2.Height
                );
        } // method outOfBounds

        /// <summary>
        /// Turns the movable object 90 degrees to the right.
        /// </summary>
        private void rotateClockwise(Creature cretin) {
            // if we're at end of enums, start over:
            if (cretin.Orientation == Creature.DIRECTION.WEST) {
                cretin.Orientation = Creature.DIRECTION.NORTH;
            }
            // otherwise, move to next direction:
            else {
                cretin.Orientation++;
            }

            // rotate image:
            //cretin.Orientation = curDir;
            cretin.Boxxy.Image.RotateFlip(RotateFlipType.Rotate270FlipXY);
            Refresh();

        } // method rotateClockwise


        #endregion motion

        #region buttons

        //Zachary Behrmann & Rob Husfeldt
        /// <summary>
        /// A button that parses text from the textbox.
        /// </summary>
        /// <param name="sender">Submit button</param>
        /// <param name="e"></param>
        private void submitButton_Click(object sender, EventArgs e) {
            string expression2;
            responseTextBox.Text = "";
            try {
                expression = parseTextBox.Text;                 // parse from textbox
                expression2 = expression;
                moves = creature.interpretCommand(expression);  // generate Queue of moves from command
                moves2 = otherCreature.interpretCommand(expression2);
                
                foreach (MotionPair mp in moves)
                {
                    animate(mp, creature);   // make each move (update GUI each time if possible)
                }
            

                foreach (MotionPair mp in moves2)
                {
                    animate(mp, otherCreature);
                }

                    
            } catch (Exception) {
                responseTextBox.Text = "Cannot process your command.\n";
            }
            finally {
                responseTextBox.Text += ": " + expression;
                parseTextBox.Text = "";
            }
        }

        

        /// <summary>
        /// Reset the textbox and creature position.
        /// </summary>
        /// <param name="sender">Refresh button</param>
        /// <param name="e"></param>
        private void refreshButton_Click(object sender, EventArgs e) {
            setUp();
        }

        /// <summary>
        /// Explain grammar
        /// </summary>
        /// <param name="sender">Help button</param>
        /// <param name="e"></param>
        private void helpButton_Click(object sender, EventArgs e) {
            String str =
                "How to enter a legal expression?\n\n" +
                "Enter a command string according to the following grammar. " +
                "Except for the first token, you must precede each tokens with at least " +
                "one space, including the period. Do not enter the quotation marks.\n\n" +
                "Remember to leave one space before the period.\n\n" +
                "Grammar: \n" +
                "S := P \".\" \n" +
                "P := P \"and\" P \n" + 
                "P := N V \n" +
                "N := \"I\" \n" +
                "V := \"go\" \n" +
                "V := \"jump\" \n" +
                "V := \"pause\" \n\n" +
                "Semantics: \n" +
                "\"move\" moves 1 \n" +
                "\"jump\" moves 2 \n" +
                "\"pause\" moves 0 \n" +
                "\"turn\" rotates 90° clockwise \n\n" +
                "Example 1: I go . \n" +
                "Example 2: I go and I go and I jump and I pause and I turn and I turn .";

            MessageBox.Show(str, "Help", MessageBoxButtons.OK, MessageBoxIcon.Question);
        }

        #endregion buttons

    } // class Parser

} // namespace ParsingProject
